/*
 * Copyright (C) 2013 Daniel Wasilew <daniel.wasilew@codeminer.org>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.codeminer.parts.server;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.codehaus.jackson.JsonNode;
import org.codehaus.jackson.map.ObjectMapper;
import org.codeminer.parts.TestApplicationBuilder;
import org.codeminer.parts.TestUtil;
import org.codeminer.parts.application.Application;
import org.codeminer.parts.application.ApplicationContext;
import org.codeminer.parts.settings.Settings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.testng.annotations.AfterGroups;
import org.testng.annotations.BeforeGroups;

import java.io.*;

import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.fail;
import static org.testng.AssertJUnit.assertEquals;

/**
 * User: Daniel Wasilew <daniel.wasilew@codeminer.org>
 * Date: 18.03.13
 * Time: 07:52
 */
public abstract class AbstractIT {
    private static final Logger log = LoggerFactory.getLogger(AbstractIT.class);

    private static Application application;

    @BeforeGroups(groups = "it")
    public static void startServer() throws Exception {
        log.info("starting server for it - tests");
        ApplicationContext applicationContext = new ApplicationContext();
        applicationContext.setHelpDir(TestUtil.createHelpDir());
        applicationContext.setConfigurationDir(TestUtil.createITSettingsDir());
        File databaseDir = TestUtil.createEmptyTMPFolder();
        log.info("databasedir -> {}", databaseDir);
        applicationContext.setDatabaseDir(databaseDir);
        applicationContext.setDatabaseScriptDir(TestUtil.createTMPDatabaseScriptFolder());

        application = TestApplicationBuilder.create(applicationContext)
                .addSettings()
                .addDerbyDatabaseManager()
                .enableDefaultPermissionManager()
                .enableUserManager()
                .enablePlayerManager()
                .enableDeviceManager()
                .enableWebAccess()
                .startup();
        log.info("started server for it - tests");
    }


    @AfterGroups(groups = "it")
    public static void stopServer() {
        log.info("stopping server for it - tests");
        application.shutdown();
        log.info("stopped server for it - tests");
    }

    private static int getServerPort() {
        Settings applicationPart = application.getApplicationPart(Settings.class);
        return applicationPart.getWebAccessPort();
    }

    protected HttpResponse execute(HttpRequest request) throws IOException {
        HttpClient client = new DefaultHttpClient();
        HttpHost httpHost = new HttpHost("localhost", getServerPort());
        return client.execute(httpHost, request);
    }

    protected JsonNode executeAndAssert(HttpRequest request) throws IOException {
        HttpResponse response = execute(request);
        assertEquals(200, response.getStatusLine().getStatusCode());
        String body = extractResponseAsString(response.getEntity());
        ObjectMapper mapper = new ObjectMapper();
        JsonNode jsonNode = mapper.readTree(body);
        JsonNode type = jsonNode.get("type");
        assertNotNull(type, "type node is null ...");
        if (type.getTextValue().equals("OK")) {
            //do nothing
        } else {
            fail("type = ERROR -> message:" +  jsonNode.get("message").getTextValue());
        }
        return jsonNode;
    }

    protected String extractResponseAsString(HttpEntity entity) throws IOException {
        InputStream content = entity.getContent();
        BufferedReader inputStreamReader = new BufferedReader(new InputStreamReader(content));
        StringBuilder result = new StringBuilder();
        String nextLine = inputStreamReader.readLine();
        while (nextLine != null) {
            result.append(nextLine);
            nextLine = inputStreamReader.readLine();
        }
        inputStreamReader.close();
        return result.toString();
    }

    protected JsonNode executeJSonPost(String json) throws IOException {
        HttpPost post = new HttpPost("/rest");
        post.setHeader("Content-Type", "application/json");
        post.setEntity(new StringEntity(json));
        return executeAndAssert(post);
    }

    protected String login(String userName, String password) throws IOException {
        String request = "{\"actionName\" : \"Login\",\"userName\" : \"" + userName + "\",\"passHash\" : \"" + DigestUtils.sha512Hex(password) + "\"}";
        JsonNode node = executeJSonPost(request);
        return node.get("sessionId").getTextValue();
    }
}
